package com.prolificinteractive.materialcalendarview;

import ohos.agp.animation.Animator;
import ohos.agp.components.AttrHelper;
import ohos.agp.components.Text;

import com.prolificinteractive.materialcalendarview.ext.TextUtils;
import com.prolificinteractive.materialcalendarview.ext.ValueAnimator;
import com.prolificinteractive.materialcalendarview.format.TitleFormatter;

class TitleChanger {

    public static final int DEFAULT_Y_TRANSLATION_DP = 20;
    private static final int animDelay = 400;
    private static final int animDuration = 150;

    private final Text title;
    private TitleFormatter titleFormatter = TitleFormatter.DEFAULT;

    private final int translate;
    private final int interpolator = Animator.CurveType.ACCELERATE_DECELERATE;

    private int orientation = MaterialCalendarView.VERTICAL;

    private long lastAnimTime = 0;
    private CalendarDay previousMonth = null;

    public TitleChanger(Text title) {
        this.title = title;
//        translate = (int) TypedValue.applyDimension(
//            TypedValue.COMPLEX_UNIT_DIP, DEFAULT_Y_TRANSLATION_DP, res.getDisplayMetrics()
//        );
        translate = AttrHelper.vp2px(DEFAULT_Y_TRANSLATION_DP, title.getContext());
    }

    public void change(final CalendarDay currentMonth) {
        long currentTime = System.currentTimeMillis();
        if (currentMonth == null) {
            return;
        }
        if (TextUtils.isEmpty(title.getText()) || (currentTime - lastAnimTime) < animDelay) {
            doChange(currentTime, currentMonth, false);
        }
        if (currentMonth.equals(previousMonth) ||
            (currentMonth.getMonth() == previousMonth.getMonth()
                && currentMonth.getYear() == previousMonth.getYear())) {
            return;
        }
        doChange(currentTime, currentMonth, true);
    }

    private ValueAnimator viewAlpha;
    private ValueAnimator viewTranslationX;
    private ValueAnimator viewTranslationY;

    private void doChange(final long now, final CalendarDay currentMonth, boolean animate) {
        if (viewAlpha != null) {
            viewAlpha.cancel();
        }
        if (viewTranslationX != null) {
            viewTranslationX.cancel();
        }
        if (viewTranslationY != null) {
            viewTranslationY.cancel();
        }
        doTranslation(title, 0);

        title.setAlpha(1);
        lastAnimTime = now;

        final CharSequence newTitle = titleFormatter.format(currentMonth);

        if (!animate) {
            title.setText(String.valueOf(newTitle));
        } else {
            final int translation = translate * (previousMonth.isBefore(currentMonth) ? 1 : -1);
            if (orientation == MaterialCalendarView.HORIZONTAL) {
                viewTranslationX = ValueAnimator.ofObject(title, title.getTranslationX(), translation * -1, ValueAnimator.Property.TRANSLATION_X);
                viewTranslationX.setDuration(animDuration);
                viewTranslationX.setInterpolatorType(interpolator);
            } else {
                viewTranslationY = ValueAnimator.ofObject(title, title.getTranslationY(), translation * -1, ValueAnimator.Property.TRANSLATION_Y);
                viewTranslationY.setDuration(animDuration);
                viewTranslationY.setInterpolatorType(interpolator);
            }
            viewAlpha = ValueAnimator.ofObject(title, title.getAlpha(), 0f, ValueAnimator.Property.ALPHA);
            viewAlpha.setDuration(animDuration);
            viewAlpha.setInterpolatorType(interpolator);
            final ValueAnimator.AnimatorListener listener = new AnimatorListener() {
                @Override
                public void onAnimationEnd(ValueAnimator animation) {
                    title.setText(String.valueOf(newTitle));
                    doTranslation(title, translation);
                    ValueAnimator tx = null;
                    ValueAnimator ty = null;
                    if (orientation == MaterialCalendarView.HORIZONTAL) {
                        tx = ValueAnimator.ofObject(title, title.getTranslationX(), 0f, ValueAnimator.Property.TRANSLATION_X);
                        tx.setDuration(animDuration);
                        tx.setInterpolatorType(interpolator);
                    } else {
                        ty = ValueAnimator.ofObject(title, title.getTranslationX(), 0f, ValueAnimator.Property.TRANSLATION_Y);
                        ty.setDuration(animDuration);
                        ty.setInterpolatorType(interpolator);
                    }
                    ValueAnimator alpha = ValueAnimator.ofObject(title, title.getAlpha(), 1f, ValueAnimator.Property.ALPHA);
                    alpha.setDuration(animDuration);
                    alpha.setInterpolatorType(interpolator);
                    if (tx != null) {
                        tx.start();
                    }
                    if (ty != null) {
                        ty.start();
                    }
                    alpha.start();
                }

                @Override
                public void onAnimationCancel(ValueAnimator animation) {
                    doTranslation(title, 0);
                    title.setAlpha(1);
                }
            };
            if (viewTranslationX != null) {
                viewTranslationX.addListener(listener);
                viewTranslationX.start();
            }
            if (viewTranslationY != null) {
                viewTranslationY.addListener(listener);
                viewTranslationY.start();
            }
            viewAlpha.addListener(listener);
            viewAlpha.start();
        }
        previousMonth = currentMonth;
    }

    private void doTranslation(final Text title, final int translate) {
        if (orientation == MaterialCalendarView.HORIZONTAL) {
            title.setTranslationX(translate);
        } else {
            title.setTranslationY(translate);
        }
    }

    public void setTitleFormatter(final TitleFormatter titleFormatter) {
        this.titleFormatter = titleFormatter == null ? TitleFormatter.DEFAULT : titleFormatter;
    }

    public void setOrientation(int orientation) {
        this.orientation = orientation;
    }

    public int getOrientation() {
        return orientation;
    }

    public void setPreviousMonth(CalendarDay previousMonth) {
        this.previousMonth = previousMonth;
    }
}
